import {CreateMotionWindow} from "../ui/CreateMotionWindow";
import {MotionEditorWindow} from "../ui/MotionEditorWindow";

export class AnimationSheet {
    guid:string
    count:number
}

export class EffectSheet {
    guid:string
    transform:number[]
    socket?:number
    color?:string
    projection?:number
}

export class AreaSheet{
    transform:number[]
    damageFactor:number
    effectID?:string
    effectScale?:number[]
    effectColor?:string
    soundID?:string
    control?:number
    repel?:number
    levitate?:number
    debuff?:number
    attrType?:string
    attrValue?:string
}

export class SoundSheet {
    guid:string
    volume:number
}

export class EmitSheet{
    effectID:string
    // 起始位置偏移
    positionOffset:number[]
    // 每逻辑帧移动单位
    translate:number[]
    // 飞行特效相对旋转
    rotationOffset:number[]
    // 持续帧数
    aliveFrame:number
    // 飞行特效缩放
    scale:number[]
    // 判定范围缩放
    areaScale:number[]
    // 命中特效
    hitEffect:string
    // 命中特效缩放
    hitEffectScale:number[]
    // 伤害系数
    hitDamageFactor:number
    // 触发后销毁
    hitDisable?:number
    // 重复触发间隔
    hitInterval?:number
    // 重力
    gravity?:number
    // 锁敌范围
    lockDistance?:number
    // 弹道类型
    trajectoryType?:string
    // 弹道参数
    trajectoryArgs?:string
    // 附加属性类型
    attrType?:string
    // 附加属性值
    attrValue?:string
    // 颜色
    color?:string
}

export class CameraSheet {
    changeNum:number
    continueCount:number
}

export class CameraTransform {
    pos:number[]
    rot:number[]
}

export class CameraLerpTransform {
    pos:number[]
    rot:number[]
    during:number
}

export class SkyBoxColor {
    horizontalTint:number[]
    sbDuring:number
}

export class SpawnAroundBuff {
    effectType:number
    buffID:number
    range:number
}

export class MotionSheet {
    obb?:AreaSheet
    eff?:EffectSheet
    anim?:AnimationSheet
    sound?:SoundSheet
    camera?:CameraSheet
    emit?:EmitSheet
    displacement?:number[]
    levitate?:number
    flashRange?:number
    breakingPoint?:number
    cameraTransform?:CameraTransform
    cameraLerpTransform?:CameraLerpTransform
    skyBoxColor?:SkyBoxColor
    skyBoxResetDuring?:number
    invisibleDuring?:number
    spawnBuffID?:number
    spawnAroundBuff?:SpawnAroundBuff
    slotChange?:number
    countDuring?:number
    counterContactMotion?:string
    counterContactGatherMotion?:string
}

export class Motion {
    name:string
    areaEffectOnce:boolean
    motionSheets:MotionSheet[]
    motionMoveSpeed?:number
    lastModifyTimestamp?:number
}

export class ModuleMotionData extends Subdata{
    @Decorator.persistence()
    sheets: { [name:string]: Motion }

    protected initDefaultData() {
        super.initDefaultData();
        this.sheets = {}
    }
}

export class ModuleMotionC extends ModuleC<ModuleMotionS,ModuleMotionData>{
    onMotionDataChanged:Action = new mw.Action()
    onCopyDataChanged:Action = new mw.Action()
    currentSelectedSheet:string|undefined
    private copyData?:MotionSheet

    onStart(){
        this.data.onDataChange.add(this.onDataChanged,this)
        this.selectDefault()
        mw.UIService.show(MotionEditorWindow)
        if(this.currentSelectedSheet == undefined){
            setTimeout(()=>{
                mw.UIService.show(CreateMotionWindow)
            },400)
        }
    }

    initMotion(name:string,frameCount:number){
        frameCount = Math.max(0,frameCount)
        this.server.net_init_motion(name,frameCount)
    }

    getMotionCount(name:string):number{
        if(!this.data.sheets[name]) return 0

        return this.data.sheets[name].motionSheets.length
    }

    coverSheetData(index:number,newData:MotionSheet){
        this.server.net_cover_data(this.currentSelectedSheet,index,newData)
    }

    setMotionAreaEffectOnce(name:string,value:boolean){
        this.server.net_set_area_effect_once(name,value)
    }

    setMotionMoveSpeed(name:string,value:number){
        this.server.net_set_motion_move_speed(name,value)
    }

    selectNewSheet(name:string){
        if(this.data.sheets[name] == undefined) return

        this.currentSelectedSheet = name

        this.onMotionDataChanged.call()
    }

    copySheetData(sheetIndex:number){
        if(!this.currentSelectedSheet) return
        this.copyData = this.data.sheets[this.currentSelectedSheet].motionSheets[sheetIndex] || {}
        this.onCopyDataChanged.call()
    }

    pasteSheetData(selectedIndex:number){
        if(!this.currentSelectedSheet) return

        if(!this.copyData) return;

        let origData = this.data.sheets[this.currentSelectedSheet].motionSheets[selectedIndex]
        let mergeData = ModuleMotionC.mergeData(this.copyData,origData)

        this.coverSheetData(selectedIndex,mergeData)
    }

    saveData(){
        this.server.net_save_data()
    }

    deleteMotion(motionName:string){
        if(motionName == this.currentSelectedSheet){
            console.error('不可删除当前选择的Motion,请选择其他Motion再删除')
            return
        }

        this.server.net_delete_motion(motionName)
    }

    static mergeData(newData:MotionSheet, oldData:MotionSheet):MotionSheet{
        let result = new MotionSheet()

        for (const key in oldData) {
            if(!oldData[key]) continue

            result[key] = oldData[key]
        }

        for (const key in newData) {
            if(!newData[key]) continue

            result[key] = newData[key]
        }

        return result
    }

    clearSheetData(sheetIndex:number){
        if(!this.currentSelectedSheet) return

        this.coverSheetData(sheetIndex,new MotionSheet())
    }

    private onDataChanged(){
        if(this.currentSelectedSheet == undefined){
            this.selectDefault()
        }

        this.onMotionDataChanged.call()
    }

    private selectDefault(){
        let selectedName:string
        let recentTime:number = -1

        for (const key in this.data.sheets) {
            let lastModifyTime = this.data.sheets[key].lastModifyTimestamp||0

            if(lastModifyTime > recentTime){
                selectedName = key
                recentTime = lastModifyTime
            }
        }

        this.currentSelectedSheet = selectedName
    }
}

export class ModuleMotionS extends ModuleS<ModuleMotionC,ModuleMotionData>{
    onStart(){

    }

    net_init_motion(name:string,frameCount:number){
        let data = this.currentData
        if(!data.sheets[name]){
            let sheet = new Motion()
            sheet.name = name
            sheet.motionSheets = []
            data.sheets[name] = sheet
        }

        if(data.sheets[name].motionSheets.length > frameCount){
            data.sheets[name].motionSheets = data.sheets[name].motionSheets.slice(0,frameCount)
        }
        else if(data.sheets[name].motionSheets.length < frameCount){
            for (let i = data.sheets[name].motionSheets.length; i < frameCount; i++) {
                data.sheets[name].motionSheets.push(new MotionSheet())
            }
        }
        data.save(true)
    }

    net_cover_data(page:string,index: number, newData: MotionSheet) {
        this.currentData.sheets[page].motionSheets[index] = newData
        this.currentData.sheets[page].lastModifyTimestamp = Date.now() / 1000
        this.currentData.save(true)
    }

    net_set_area_effect_once(name:string,value:boolean){
        this.currentData.sheets[name].areaEffectOnce = value
        this.currentData.save(true)
    }

    net_set_motion_move_speed(name:string,value:number){
        this.currentData.sheets[name].motionMoveSpeed = value
        this.currentData.save(true)
    }

    net_save_data() {
        this.currentData.save(true)
    }

    net_delete_motion(motionName: string) {
        delete this.currentData.sheets[motionName]
        this.currentData.save(true)
    }
}